import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.util.Scanner;

import javax.media.opengl.GL;
import javax.media.opengl.glu.GLU;

import com.sun.opengl.impl.mipmap.Image;
import com.sun.opengl.util.texture.Texture;
import com.sun.opengl.util.texture.TextureData;
import com.sun.opengl.util.texture.TextureIO;

public class Rocket {
	GL gl;
	GLU glu;
	private int shaderprogram,shaderprogram2,list_id;
	private int tree[],leaf[];//textures
	private int vert_shader, frag_shader, vert_shader2, frag_shader2;
	private int rocket_max,rocket_height,cur_rocket, max_puff,cur_puff,start_puff, puff_concetration ;
	private Vector3D start, end;
	private float yaw, pitch, max_len,x_disp,y_disp,z_disp,radius,high;
	private Vector3D player,inverse_pos,direction;
	private boolean rise,flight,smoke,reflect;
	private Vector3D inverse_puff[];//инверсный след и его дисперсия
	private Vector3D puff_speed[];
	private Vector3D rockets[];//центры ракет
	private Vector3D speeds[];//вектора их скоростей
	private Vector3D rocket_angle[];//их углы эйлера
	
	private Vector3D conus[];//основание дерева
	Texture boxTexture1, boxTexture2;
	
	public Rocket(GL gl_, GLU glu_){
		gl=gl_;
		glu=glu_;
		init();
		loadShader();
		loadShader2();
		CreateTexture(null);
	}

	private void init(){
		direction = new Vector3D();//направление траектории полета и углы поворота для ракеты
		inverse_pos = new Vector3D(0,250,0);
		player = new Vector3D();
		reflect = true;
		yaw = 0; pitch = 0;
		high = 80;//start engine high OZ
		max_puff = 500;//buffer limit
		max_len = 400;//max of puffs
		x_disp = 8f;
		y_disp = 4f;//smoke dispersion (bigger number - less of dispersion)
		z_disp = 8f;
		puff_concetration = 25;//concentration in one frame
		radius = 0.9f;//puff radius
		cur_puff = 0;
		start_puff = 0;
		smoke = false;
		puff_speed = new Vector3D[max_puff];
		inverse_puff = new Vector3D[max_puff];
		start = new Vector3D(0,0,0);
		rise = true; flight = false;
		end = new Vector3D(0,0,0);
		tree = new int[1];
		leaf = new int[1];
		rocket_max = 1;
		list_id = 0;
		cur_rocket = 0;
		rocket_height = 6;
		speeds = new Vector3D[rocket_max];
		rockets = new Vector3D[rocket_max];
		rocket_angle = new Vector3D[rocket_max];
		smoke_init();
		rocket_init();//location of trees
		conus = new Vector3D[9];// в основании дерева лежит восьмиугольник
		conus_init();
		
		
	}
	private void smoke_init() {
		for(int i = 0; i < max_puff; i++) {
			puff_speed[i] = new Vector3D(((float)Math.random() - 0.5f)/x_disp,((float)Math.random() - 0.5f)/y_disp,((float)Math.random() - 0.5f)/z_disp);
			inverse_puff[i] = new Vector3D();
		}
	}
	public static float rnd() {
		return (float)Math.random();
	}
	private void start_ring(int i) {
		float d,f,g;
		int sign = 1;
		d = puff_speed[i].x;
		f = puff_speed[i].z;
		if(rnd() >= 0.5f) sign = -1;
		g = (rnd() - 0.5f)*6f;
		puff_speed[i].x = (float) ((float)sign*Math.sqrt(9f - (float)Math.pow(g,2f)));
		puff_speed[i].z = g;
		inverse_puff[i] = Vector3D.add(inverse_puff[i], puff_speed[i]);
		puff_speed[i].x = d;
		puff_speed[i].z = f;
	}
	private void draw_inverse(boolean fly) {
		Vector3D pos = new Vector3D();
		boolean start = false;
		pos = inverse_pos;
		if(!smoke && !fly) return;
		if(!smoke && reflect && fly) {
			if(cur_puff < start_puff) {
				if((max_puff + cur_puff) - start_puff >= max_len) 
					smoke = true;
			}
			else if(cur_puff - start_puff >= max_len){
				smoke = true;
			}
		}
		
		if(fly && reflect) {
			
			if(cur_puff == start_puff && !smoke) start = true;
			if(start) cur_puff += puff_concetration*9;
			else cur_puff += puff_concetration;
		}
		if(smoke && reflect) {
			start_puff += puff_concetration;
			if(start_puff >= max_puff && reflect) start_puff -= max_puff;
			if(cur_puff == start_puff) {
				smoke = false;
				return;
			}
		}
		if(start_puff >= max_puff && reflect) start_puff -= max_puff; //ring buffer
		if(cur_puff >= max_puff && fly && reflect) {
			if(start) {
				for(int i = cur_puff - 9*puff_concetration; i < max_puff; i++) {
					inverse_puff[i] = Vector3D.sub(pos,Vector3D.div(direction, high/(4*rnd())));
				}
				for(int i = 0; i <= cur_puff - max_puff; i++) {
					inverse_puff[i] = Vector3D.sub(pos,Vector3D.div(direction, high/(4*rnd())));
				}
			}
			else {
				for(int i = cur_puff - puff_concetration; i < max_puff; i++) {
					inverse_puff[i] = Vector3D.sub(pos,Vector3D.div(direction, high/(4*rnd())));
				}
				for(int i = 0; i <= cur_puff - max_puff; i++) {
					inverse_puff[i] = Vector3D.sub(pos,Vector3D.div(direction, high/(4*rnd())));
				}
			}
			cur_puff -= max_puff;
		}
		else if(fly && reflect){
			if(start) 
			for(int i = cur_puff - 9*puff_concetration; i <= cur_puff; i++) {
				inverse_puff[i] = Vector3D.sub(pos,Vector3D.div(direction, high/(2*rnd())));
			}
			else for(int i = cur_puff - puff_concetration; i <= cur_puff; i++) {
				inverse_puff[i] = Vector3D.sub(pos,Vector3D.div(direction, high/(2*rnd())));
			}
		}
		Vector3D point1 = new Vector3D(0,-radius,-radius);
	    Vector3D point2 = new Vector3D(0,radius,-radius);
	    Vector3D point3 = new Vector3D(0,radius,radius);
	    Vector3D point4 = new Vector3D(0,-radius,radius);
	    if(!reflect) pitch = -pitch;

	    Matrix4x4 maty = new Matrix4x4();
	    Matrix4x4 matz = new Matrix4x4();
	    yaw = -yaw;   			    
	    maty = Matrix4x4.set((float)Math.cos(pitch),0,(float)Math.sin(pitch),0,
                   0,1,0,0,
                   (float)-Math.sin(pitch),0,(float)Math.cos(pitch),0,
                   0,0,0,1);
    

	    matz = Matrix4x4.set((float)Math.cos(yaw+Atmosphere.pi),(float)-Math.sin(yaw+Atmosphere.pi),0,0,
    		(float)Math.sin(yaw+Atmosphere.pi),(float)Math.cos(yaw+Atmosphere.pi),0,0,
                   0,0,1,0,
                   0,0,0,1);
	   // System.out.println(inverse_puff[start_puff].x() + " , " + inverse_puff[start_puff].y() + " , " + inverse_puff[start_puff].z());
	    point1 = Matrix4x4.mult(Matrix4x4.mult(matz,maty),point1);
	    point2 = Matrix4x4.mult(Matrix4x4.mult(matz,maty),point2);
	    point3 = Matrix4x4.mult(Matrix4x4.mult(matz,maty),point3);
	    point4 = Matrix4x4.mult(Matrix4x4.mult(matz,maty),point4);
	    
		gl.glUseProgram(shaderprogram2);
		setShader2(pos);
	    gl.glEnable(GL.GL_ALPHA_TEST);
	    gl.glEnable(GL.GL_BLEND);
	    gl.glBlendFunc(GL.GL_SRC_ALPHA,GL.GL_ONE_MINUS_SRC_ALPHA);
	    gl.glDepthMask(false);
	    gl.glBegin(GL.GL_QUADS);
		if(cur_puff > start_puff) {
			for(int i = start_puff; i <= cur_puff; i++) {
				if(start) {
					start_ring(i);
				}
				else inverse_puff[i] = Vector3D.add(inverse_puff[i], puff_speed[i]);
				gl.glTexCoord2d(0,0);
		    	gl.glVertex3f(point1.x()+inverse_puff[i].x(),point1.y()+inverse_puff[i].y(),point1.z()+inverse_puff[i].z());

		    	gl.glTexCoord2d(1,0);
		    	gl.glVertex3f(point2.x()+inverse_puff[i].x(),point2.y()+inverse_puff[i].y(),point2.z()+inverse_puff[i].z());

		    	gl.glTexCoord2d(1,1);
		    	gl.glVertex3f(point3.x()+inverse_puff[i].x(),point3.y()+inverse_puff[i].y(),point3.z()+inverse_puff[i].z());

		    	gl.glTexCoord2d(0,1);
		    	gl.glVertex3f(point4.x()+inverse_puff[i].x(),point4.y()+inverse_puff[i].y(),point4.z()+inverse_puff[i].z());
			}
		}
		else {
			//System.out.println(start_puff + "->" + cur_puff);
			for(int i = start_puff; i < max_puff; i++) {
				if(start) {//make start ring
					start_ring(i);
				}
				else inverse_puff[i] = Vector3D.add(inverse_puff[i], puff_speed[i]);
				gl.glTexCoord2d(0,0);
		    	gl.glVertex3f(point1.x()+inverse_puff[i].x(),point1.y()+inverse_puff[i].y(),point1.z()+inverse_puff[i].z());

		    	gl.glTexCoord2d(1,0);
		    	gl.glVertex3f(point2.x()+inverse_puff[i].x(),point2.y()+inverse_puff[i].y(),point2.z()+inverse_puff[i].z());

		    	gl.glTexCoord2d(1,1);
		    	gl.glVertex3f(point3.x()+inverse_puff[i].x(),point3.y()+inverse_puff[i].y(),point3.z()+inverse_puff[i].z());

		    	gl.glTexCoord2d(0,1);
		    	gl.glVertex3f(point4.x()+inverse_puff[i].x(),point4.y()+inverse_puff[i].y(),point4.z()+inverse_puff[i].z());
			}
			for(int i = 0; i <= cur_puff; i++) {
				if(start) {
					start_ring(i);
				}
				else inverse_puff[i] = Vector3D.add(inverse_puff[i], puff_speed[i]);
				gl.glTexCoord2d(0,0);
		    	gl.glVertex3f(point1.x()+inverse_puff[i].x(),point1.y()+inverse_puff[i].y(),point1.z()+inverse_puff[i].z());

		    	gl.glTexCoord2d(1,0);
		    	gl.glVertex3f(point2.x()+inverse_puff[i].x(),point2.y()+inverse_puff[i].y(),point2.z()+inverse_puff[i].z());

		    	gl.glTexCoord2d(1,1);
		    	gl.glVertex3f(point3.x()+inverse_puff[i].x(),point3.y()+inverse_puff[i].y(),point3.z()+inverse_puff[i].z());

		    	gl.glTexCoord2d(0,1);
		    	gl.glVertex3f(point4.x()+inverse_puff[i].x(),point4.y()+inverse_puff[i].y(),point4.z()+inverse_puff[i].z());
			}
			if(start) {
				start = false;
				//puff_concetration /= 9;
			}
		}
		gl.glEnd();
	    gl.glDepthMask(true);
	    gl.glDisable(GL.GL_ALPHA_TEST);
	    gl.glDisable(GL.GL_BLEND);
		gl.glUseProgram(0);
		
	}
	private void rocket_init(){
	    for(int i = 0; i < rocket_max; i++) {
	    	speeds[i] = new Vector3D(0,0,0);
	    	rocket_angle[i] = new Vector3D(0,0,0);
	        rockets[i] = new Vector3D();
	        while(true) {
	        rockets[i].x = 0f;
	        rockets[i].y = 250f;
	       	rockets[i].z = 0f;//rnd()*50f;
	        if(rockets[i].x > -10 && rockets[i].x < 90 && rockets[i].y > -10 && rockets[i].y < 90) continue;
	        else if(rockets[i].x > 150 && rockets[i].x < 240 && rockets[i].y > -10 && rockets[i].y < 90) continue;
	        else break;
	        }
	    }
	}

	private void conus_init(){
		float approx = (float)Math.sqrt(2f)/2f;//
	    conus[0] = new Vector3D(-1f,0f,0f);
	    conus[1] = new Vector3D(-approx,approx,0f);
	    conus[2] = new Vector3D(0f,1f,0f);
	    conus[3] = new Vector3D(approx,approx,0f);
	    conus[4] = new Vector3D(1f,0f,0f);
	    conus[5] = new Vector3D(approx,-approx,0f);
	    conus[6] = new Vector3D(0f,-1f,0f);
	    conus[7] = new Vector3D(-approx,-approx,0f);
	    conus[8] = new Vector3D(-1f,0f,0f);
	}
	private void CreateTexture(Image image)
	 {
		 URL imageURL= this.getClass().getResource(
				 "cloud.png");
	        
		 TextureData data=null;
		 try {
			 data = TextureIO.newTextureData(
					 imageURL.openStream(),false, "png");
			 boxTexture1 = TextureIO.newTexture(data);
		 } catch (IOException exc) {
			 exc.printStackTrace();
			 System.exit(1);
		 }       
	        
		 gl.glEnable(GL.GL_TEXTURE_2D);
		 
		 gl.glGenTextures(1,leaf, 0);
		 gl.glBindTexture(GL.GL_TEXTURE_2D, leaf[0]);
		 gl.glTexImage2D(GL.GL_TEXTURE_2D, 0,GL.GL_RGBA,data.getWidth(),data.getHeight(),0,GL.GL_RGBA,
				 GL.GL_UNSIGNED_BYTE,data.getBuffer());
//		 gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
//		 gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
		 URL imageURL2= this.getClass().getResource(
				 "rocket.png");
	            
		 TextureData data2=null;
		 try {
			 data2 = TextureIO.newTextureData(
					 imageURL2.openStream(),false, "png");
			 boxTexture2 = TextureIO.newTexture(data2);
		 } catch (IOException exc) {
			 exc.printStackTrace();
			 System.exit(1);
		 }       
	     
		 gl.glGenTextures(1,tree,0);
		 gl.glBindTexture(GL.GL_TEXTURE_2D, tree[0]);
	     
		 gl.glTexImage2D(GL.GL_TEXTURE_2D,
				 0,GL.GL_RGBA,data.getWidth(),
				 data.getHeight(),0,GL.GL_RGBA,
				 GL.GL_UNSIGNED_BYTE,data.getBuffer());
//		 gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
//		 gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
	 }
	
	 private void loadShader(){
		 vert_shader = gl.glCreateShader(GL.GL_VERTEX_SHADER);
	        frag_shader = gl.glCreateShader(GL.GL_FRAGMENT_SHADER);
	        
	        BufferedReader brv = null;
			try {
				brv = new BufferedReader(
						new FileReader(
								"src/lighting.vert"));
			} catch (FileNotFoundException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
	        String vsrc = "";
	        String line;
	        try {
				while ((line=brv.readLine()) != null) {
				  vsrc += line + "\n";
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        gl.glShaderSource(vert_shader, 1,
	        		new String[] {vsrc}, (int[])null, 0);
	        gl.glCompileShader(vert_shader);
	        
	        BufferedReader brf = null;
			try {
				brf = new BufferedReader(
						new FileReader(
								"src/lighting.frag"));
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        String fsrc = "";
	        String lines;
	        try {
				while ((lines=brf.readLine()) != null) {
				  fsrc += lines + "\n";
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        gl.glShaderSource(frag_shader, 1,
	        		new String[] {fsrc}, (int[])null, 0);
	        gl.glCompileShader(frag_shader);
	        
	        shaderprogram = gl.glCreateProgram();
	        gl.glAttachShader(shaderprogram, vert_shader);
	        gl.glAttachShader(shaderprogram, frag_shader);
	        gl.glLinkProgram(shaderprogram);
	        gl.glValidateProgram(shaderprogram);
	 }
	 private void loadShader2(){
		 vert_shader2 = gl.glCreateShader(GL.GL_VERTEX_SHADER);
	        frag_shader2 = gl.glCreateShader(GL.GL_FRAGMENT_SHADER);
	        
	        BufferedReader brv = null;
			try {
				brv = new BufferedReader(
						new FileReader(
								"src/inverse.vert"));
			} catch (FileNotFoundException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
	        String vsrc = "";
	        String line;
	        try {
				while ((line=brv.readLine()) != null) {
				  vsrc += line + "\n";
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        gl.glShaderSource(vert_shader2, 1,
	        		new String[] {vsrc}, (int[])null, 0);
	        gl.glCompileShader(vert_shader2);
	        
	        BufferedReader brf = null;
			try {
				brf = new BufferedReader(
						new FileReader(
								"src/inverse.frag"));
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        String fsrc = "";
	        String lines;
	        try {
				while ((lines=brf.readLine()) != null) {
				  fsrc += lines + "\n";
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        gl.glShaderSource(frag_shader2, 1,
	        		new String[] {fsrc}, (int[])null, 0);
	        gl.glCompileShader(frag_shader2);
	        
	        shaderprogram2 = gl.glCreateProgram();
	        gl.glAttachShader(shaderprogram2, vert_shader2);
	        gl.glAttachShader(shaderprogram2, frag_shader2);
	        gl.glLinkProgram(shaderprogram2);
	        gl.glValidateProgram(shaderprogram2);
	 }
	 private void setShader2(Vector3D posit){
		 gl.glActiveTexture(GL.GL_TEXTURE0);
		    gl.glBindTexture(GL.GL_TEXTURE_2D,leaf[0]-1);
	        gl.glUniform1i(gl.glGetUniformLocation(
	        		shaderprogram2, "cloud"), 0);
	        gl.glUniform3f(gl.glGetUniformLocation(
	        		shaderprogram2, "center"), posit.x(), posit.y(), posit.z());
	 }
	 private void setShader(Vector3D pos,int tex){
		 
		 	gl.glActiveTexture(GL.GL_TEXTURE1);
		    gl.glBindTexture(GL.GL_TEXTURE_2D,1);
	        gl.glUniform1i(gl.glGetUniformLocation(
	        		shaderprogram, "envMap"), 1);
	        gl.glUniform1f(gl.glGetUniformLocation(
	        		shaderprogram, "shad"), 0f);
	        
	        gl.glActiveTexture(GL.GL_TEXTURE0);
		    if(tex == 0) gl.glBindTexture(GL.GL_TEXTURE_2D,leaf[0]-1);
		    else gl.glBindTexture(GL.GL_TEXTURE_2D,tree[0]-1);
	        gl.glUniform1i(gl.glGetUniformLocation(
	        		shaderprogram, "leaf"), 0);
	        
	        gl.glUniform3f(gl.glGetUniformLocation(
	        		shaderprogram, "eyePos"), pos.x,pos.y,pos.z);
	        gl.glUniform3f(gl.glGetUniformLocation(
	        		shaderprogram, "lightPos"), Atmosphere.sun.x,Atmosphere.sun.y,Atmosphere.sun.z);
	 }
	 public static Vector3D normal(Vector3D A, Vector3D B, Vector3D C) {
		    float x = A.y()*(B.z() - C.z()) + B.y()*(C.z() - A.z()) + C.y()*(A.z() - B.z());
		    float y = A.z()*(B.x() - C.x()) + B.z()*(C.x() - A.x()) + C.z()*(A.x() - B.x());
		    float z = A.x()*(B.y() - C.y()) + B.x()*(C.y() - A.y()) + C.x()*(A.y() - B.y());
		    Vector3D result = new Vector3D(-x,-y,-z);
		    result.normalize();
		    return result;
		}
	 public boolean draw(Camera camera, boolean fire, boolean ref,Vector3D target) {
		 boolean ret_val = false;
		 reflect = ref;
		 player = camera.pos;
		 yaw = camera.yaw;
		 pitch = camera.pitch;
		 end = target;
		 float d_yaw = 0, d_pitch = 0;
		 if(MyJoglCanvas.player_field == 2) {
			 start.y = 250f;
		 }
		 else {
			 start.y = 0f;
		 }
		 start.z = high;
		 end.z = 0;
	//	 System.out.println("start = " + start.x + " " + start.y + " " + start.z);
	//	 System.out.println("end = " + end.x + " " + end.y + " " + end.z);
		 direction = Vector3D.sub(end, start);
		 float pitch = (float)Math.atan(direction.x/-direction.y);
		 float yaw = (float)Math.atan(Math.sqrt(direction.x*direction.x + direction.y*direction.y)/direction.z);
		 //start.z = high;//not necessary
		 
		 float zsp = 1.0f;
		 float xsp = (float)((end.x - start.x)/high*zsp);//скорости после набора высоты
		 float ysp = (float)((end.y - start.y)/high*zsp);
		    if(fire && reflect) {
		    	cur_rocket++;
		    	if(cur_rocket <= 1) { 
			    	rockets[cur_rocket-1].x = start.x;
			    	rockets[cur_rocket-1].y = start.y;
			    	rockets[cur_rocket-1].z = 0f;
		    	}
		    	else cur_rocket--;
		    }
		    if(fire) flight = true;
	 		float pi = (float) Math.PI;
	 		if(cur_rocket == 0) {
	 			draw_inverse(false);
	 			return ret_val;
	 		}
	 		if(reflect)
	 		for(int a = 0; a < cur_rocket; a++) {
		 		if(rise && rockets[a].z < high && flight) {
		 			float direct = 1f;
		 			if(MyJoglCanvas.player_field == 2) direct = -1f;
		 			rocket_angle[a].x += direct*(yaw)/(high/2f);//change pitch and yaw "pi -" 
		 			rocket_angle[a].y += direct*(pi - pitch)/(high/2f);//before starting engine
		 			rocket_angle[a].z += 0;
		 			rockets[a].z += 2f;
		 		}
		 		else if(rise && rockets[a].z >= high && flight) {
		 			rise = false;
		 			speeds[a].x = xsp;
		 			speeds[a].y = ysp;
		 			//start engine
		 			speeds[a].z = zsp;
		 			//System.out.println(yaw + " " + pitch);
		 			d_yaw = (-yaw - rocket_angle[a].x)/2f;
		 			d_pitch = (-pitch - rocket_angle[a].y)/2f;
		 		}
		 		else if(rockets[a].z < -1 && flight) {
		 			rockets[a].x = end.x;
		 			rockets[a].y = end.y; 
		 			rocket_angle[a].x = 0;
		 			rocket_angle[a].y = 0;
		 			rocket_angle[a].z = 0;//landing
		 			speeds[a].x = 0;
		 			speeds[a].y = 0;
		 			speeds[a].z = 0;
		 			flight = false;
		 			cur_rocket = 0;
		 			rise = true;
		 			ret_val = true;
		 		}
		 		if(!rise && flight){
		 			rockets[a].x += speeds[a].x;
		 			rockets[a].y += speeds[a].y;
		 			rockets[a].z -= speeds[a].z;
		 			float direct = 1f;
		 			if(MyJoglCanvas.player_field == 2) direct = -1f;
			 		rocket_angle[a].x =  direct*yaw;//change pitch and yaw " -" 
			 		rocket_angle[a].y =  direct*(pi-pitch);
			 		rocket_angle[a].z += (pi - pitch - yaw)/8f;  
		 		}
	 		}
	 		gl.glDisable(GL.GL_CULL_FACE);
	 		gl.glActiveTexture(GL.GL_TEXTURE0);
	 		gl.glColor3f(0.4f,0.2f,0f);
	 		gl.glBindTexture(GL.GL_TEXTURE_2D,tree[0]-1);
			 gl.glUseProgram(shaderprogram);
			 setShader(player,1);
	 		gl.glBegin(GL.GL_QUADS);
	 		float scale = 1.0f;
	 		float offset = 0f;
	 		for(int a = 0; a < cur_rocket; a++) {
	 			if(rockets[a].x == 100 && rockets[a].y == 100) continue;
	 			Matrix4x4 matx = new Matrix4x4(),maty  = new Matrix4x4(),matz  = new Matrix4x4();
	 			maty = Matrix4x4.set((float)Math.cos(rocket_angle[a].y),0,(float)Math.sin(rocket_angle[a].y),0,
	                    0,1,0,0,
	                    (float)-Math.sin(rocket_angle[a].y),0,(float)Math.cos(rocket_angle[a].y),0,
	                    0,0,0,1);
	 			
		 	    matz = Matrix4x4.set((float)Math.cos(rocket_angle[a].z),(float)-Math.sin(rocket_angle[a].z),0,0,
		     		(float)Math.sin(rocket_angle[a].z),(float)Math.cos(rocket_angle[a].z),0,0,
		                    0,0,1,0,
		                    0,0,0,1);
		 	    
		 	    matx=Matrix4x4.set(1, 0, 0, 0,
		 	    		0, (float)Math.cos(rocket_angle[a].x), (float)-Math.sin(rocket_angle[a].x), 0,
		 	    		0, (float)Math.sin(rocket_angle[a].x), (float)Math.cos(rocket_angle[a].x),0,
		 	    		0, 0, 0, 1);
	 	        Vector3D tree_normal1 = new Vector3D();
	 	        Vector3D a1;
	 	        Vector3D a2;
	 	        Vector3D a3;
	 	        Vector3D a4;
 				float width = 0.32f; 
 				float width1 = 0.32f;
	 	        for(int i = 0; i < 8; i += 2) {//wings
	 	        	a1 = new Vector3D(conus[i].x*width,conus[i].y*width, - rocket_height*scale/2);
		 	        a2 = new Vector3D(conus[i+1].x*width,conus[i+1].y*width,scale - rocket_height*scale/2);
		 	        a3 = new Vector3D(conus[i+2].x*width,conus[i+2].y*width, - rocket_height*scale/2);
		 	        a4 = new Vector3D(conus[i+1].x*4*width,conus[i+1].y*4*width,-scale - rocket_height*scale/2);
		 	        Vector3D a5 = new Vector3D(0,0,-0.8f*scale - rocket_height*scale/2);
		 	        a1 = Matrix4x4.mult(Matrix4x4.mult(Matrix4x4.mult(matx,maty),matz),a1);
				    a2 = Matrix4x4.mult(Matrix4x4.mult(Matrix4x4.mult(matx,maty),matz),a2);
				    a3 = Matrix4x4.mult(Matrix4x4.mult(Matrix4x4.mult(matx,maty),matz),a3);//rotation
				    a4 = Matrix4x4.mult(Matrix4x4.mult(Matrix4x4.mult(matx,maty),matz),a4);
				    a5 = Matrix4x4.mult(Matrix4x4.mult(Matrix4x4.mult(matx,maty),matz),a5);
				    
				    a1.setXYZ(a1.x + rockets[a].x,a1.y + rockets[a].y,a1.z + rockets[a].z + rocket_height*scale/2);
 				    a2.setXYZ(a2.x + rockets[a].x,a2.y + rockets[a].y,a2.z + rockets[a].z + rocket_height*scale/2);
 				    a3.setXYZ(a3.x + rockets[a].x,a3.y + rockets[a].y,a3.z + rockets[a].z + rocket_height*scale/2);//moving
 				    a4.setXYZ(a4.x + rockets[a].x,a4.y + rockets[a].y,a4.z + rockets[a].z + rocket_height*scale/2);
 				    a5.setXYZ(a5.x + rockets[a].x,a5.y + rockets[a].y,a5.z + rockets[a].z + rocket_height*scale/2);
 				    inverse_pos = a5; //tail of rocket and start of inverse tail
				    tree_normal1 = normal(a3,a2,a1);
					gl.glNormal3f(tree_normal1.x,tree_normal1.y,tree_normal1.z);
					gl.glTexCoord2d(0,0);
	 				gl.glVertex3f(a1.x,a1.y,a1.z);
	 				
	 				tree_normal1 = normal(a3,a2,a1);
	 				gl.glNormal3f(tree_normal1.x,tree_normal1.y,tree_normal1.z);
	 				gl.glTexCoord2d(1,0);
	 				gl.glVertex3f(a2.x,a2.y,a2.z);
	 				
	 				tree_normal1 = normal(a3,a2,a1);
	 				gl.glNormal3f(tree_normal1.x,tree_normal1.y,tree_normal1.z);
	 				gl.glTexCoord2d(1,1);
	 				gl.glVertex3f(a3.x,a3.y,a3.z);
	 				
	 				tree_normal1 = normal(a4,a3,a2);
	 				gl.glNormal3f(tree_normal1.x,tree_normal1.y,tree_normal1.z);
	 				gl.glTexCoord2d(0,1);
	 				gl.glVertex3f(a4.x,a4.y,a4.z);	
	 	        }
	 			for(int j = 0; j < rocket_height; j++) {//tube
		 			for(int i = 0; i < 8; i++) {
		 				width = 0.32f; 
		 				width1 = 0.32f;
		 				if(j == rocket_height -2) {
		 					width1 = 0f;

		 				}
		 				if(j == rocket_height -3) {
		 					width = 0.38f;

		 				}
		 				if(j == rocket_height -4) {
		 					width1 = 0.38f;
		 					width = 0.38f;
		 				}
		 				if(j == rocket_height -5) {
		 					width1 = 0.38f;

		 				}



		 				    Vector3D tree_normal = new Vector3D();
		 				    a1 = new Vector3D(conus[i].x*width, conus[i].y*width, j*scale - rocket_height*scale/2);
		 				    a2 = new Vector3D(conus[i+1].x*width, conus[i+1].y*width, j*scale - rocket_height*scale/2);//creating default model
		 				    a3 = new Vector3D(conus[i+1].x*width1, conus[i+1].y*width1, min(rocket_height-1,(j+1))*scale - rocket_height*scale/2);
		 				    a4 = new Vector3D(conus[i].x*width1, conus[i].y*width1, min(rocket_height-1,(j+1))*scale - rocket_height*scale/2); 
		 					
		 				    Vector3D a1_;
		 				    Vector3D a2_;
		 				    Vector3D a3_;
		 				    
		 				    if(i == 0) {
		 				    	a1_ = new Vector3D(conus[7].x*width,conus[7].y*width,j*scale - rocket_height*scale/2);
		 				    }
		 				    else {
		 				    	a1_ = new Vector3D(conus[i-1].x*width ,conus[i-1].y*width ,j*scale - rocket_height*scale/2);
		 				    }
		 				    if(i == 7) {
		 				    	a2_ = new Vector3D(conus[0].x*width ,conus[0].y*width,j*scale - rocket_height*scale/2);
			 				    a3_ = new Vector3D(conus[0].x*width1,conus[0].y*width1 ,min(rocket_height-1,(j+1))*scale - rocket_height*scale/2);
		 				    }
		 				    else {
		 				    	a2_ = new Vector3D(conus[i+1].x*width ,conus[i+1].y*width,j*scale - rocket_height*scale/2);
			 				    a3_ = new Vector3D(conus[i+1].x*width1,conus[i+1].y*width1,min(rocket_height-1,(j+1))*scale - rocket_height*scale/2);
		 				    }
		 				    a1 = Matrix4x4.mult(Matrix4x4.mult(Matrix4x4.mult(matx,maty),matz),a1);
		 				    a2 = Matrix4x4.mult(Matrix4x4.mult(Matrix4x4.mult(matx,maty),matz),a2);
		 				    a3 = Matrix4x4.mult(Matrix4x4.mult(Matrix4x4.mult(matx,maty),matz),a3);//rotation
		 				    a4 = Matrix4x4.mult(Matrix4x4.mult(Matrix4x4.mult(matx,maty),matz),a4);
		 				    
		 				    a1_ = Matrix4x4.mult(Matrix4x4.mult(Matrix4x4.mult(matx,maty),matz),a1_);
		 				    a2_ = Matrix4x4.mult(Matrix4x4.mult(Matrix4x4.mult(matx,maty),matz),a2_);
		 				    a3_ = Matrix4x4.mult(Matrix4x4.mult(Matrix4x4.mult(matx,maty),matz),a3_);
		 				    
		 				    a1.setXYZ(a1.x + rockets[a].x,a1.y + rockets[a].y,a1.z + rockets[a].z + rocket_height*scale/2);
		 				    a2.setXYZ(a2.x + rockets[a].x,a2.y + rockets[a].y,a2.z + rockets[a].z + rocket_height*scale/2);
		 				    a3.setXYZ(a3.x + rockets[a].x,a3.y + rockets[a].y,a3.z + rockets[a].z + rocket_height*scale/2);//moving
		 				    a4.setXYZ(a4.x + rockets[a].x,a4.y + rockets[a].y,a4.z + rockets[a].z + rocket_height*scale/2);
		 				    
		 				    a1_.setXYZ(a1_.x + rockets[a].x,a1_.y + rockets[a].y,a1_.z + rockets[a].z + rocket_height*scale/2);
		 				    a2_.setXYZ(a2_.x + rockets[a].x,a2_.y + rockets[a].y,a2_.z + rockets[a].z + rocket_height*scale/2);
		 				    a3_.setXYZ(a3_.x + rockets[a].x,a3_.y + rockets[a].y,a3_.z + rockets[a].z + rocket_height*scale/2);
		 				    
		 				    tree_normal = normal(a1_,a2,a4);
		 				    gl.glNormal3f(tree_normal.x,tree_normal.y,tree_normal.z);
		 					gl.glTexCoord2d(0,0);
			 				gl.glVertex3f(a1.x,a1.y,a1.z);
			 				
			 				tree_normal = normal(a1,a2_,a3);
			 				gl.glNormal3f(tree_normal.x,tree_normal.y,tree_normal.z);
			 				gl.glTexCoord2d(1,0);
			 				gl.glVertex3f(a2.x,a2.y,a2.z);
			 				
			 				tree_normal = normal(a1,a2_,a3);
			 				gl.glNormal3f(tree_normal.x,tree_normal.y,tree_normal.z);
			 				gl.glTexCoord2d(1,1);
			 				gl.glVertex3f(a3.x,a3.y,a3.z);
			 				
			 				tree_normal = normal(a1_,a2,a4);
			 				gl.glNormal3f(tree_normal.x,tree_normal.y,tree_normal.z);
			 				gl.glTexCoord2d(0,1);
			 				gl.glVertex3f(a4.x,a4.y,a4.z);
		 			}
		 		}
	 		}
	 		gl.glEnd();
	 		gl.glUseProgram(0);
	 		gl.glEnable(GL.GL_CULL_FACE);
	 		gl.glEnable(GL.GL_TEXTURE_2D);
 			if(rise && rockets[0].z < 60 && flight) {
	 			draw_inverse(false);
	 		}
	 		else if(rise && rockets[0].z >= 60 && flight) {
	 			draw_inverse(false);
	 		}
	 		else if(rockets[0].z < 0 && flight) {
	 			draw_inverse(false);
		 	}
	 		if(!rise && flight){
	 			draw_inverse(true);
	 		}
	 		//gl.glUseProgram(0);
	 		return ret_val;
	}
	private float min(int a, int b) {
		return a > b ? b : a;
	}
	private float max(int a, int b) {
		return a > b ? a : b;
	}
}